package ewu.expressions

import ewu._
import scala.collection.mutable.ArrayBuffer

/**
 * Die Klasse ExpArray ist fuer die Darstellung von Arrays
 * verfuegbar. Die Grenzen des Arrays werden ueber die
 * Indexrange irange oder durch zwei Expressions "rfromE"
 * und "rtoE" festgelegt.
 */

class ExpArray(irange: IndexRange, rfromE: Expression, rtoE: Expression) extends Expression {
  
  def this(irange: IndexRange) = this(irange, null, null)
  def this(rfromE: Expression, rtoE: Expression) = this(
    new IndexRange(
      rfromE match {
        case x:Number => x.value.toInt
        case _ => 0
      }, 
      rtoE match {
        case x: Number => x.value.toInt
        case _ => 0
      }))

  
  var range = irange
  var fromE = rfromE
  var toE = rtoE
  var ifirst: Int = range.first
  var ilast: Int = range.last
  private var array: Array[Expression] = new Array[Expression](0);

  if (!range.isEmpty) {
    initArray()
  }

  def initArray() : Unit = {
    array = new Array[Expression](ilast - ifirst + 1)
  }
  
  def setExpRange(from: Expression, to: Expression) : Unit = {
    fromE = from
    toE = to
    fromE match {
      case x:Number => ifirst = x.value.toInt
      case _ => 
    }
    toE match {
      case x:Number => ilast = x.value.toInt
      case _ => 
    }
    range = new IndexRange(ifirst, ilast)
    var na = new Array[Expression](ilast-ifirst+1)
    for(i <- 0 to array.length-1) {
      na(i) = array(i)
    }
    array = na
  }
  
  /*
   * Falls Indexgrenzen noch nicht gesetzt, werden anhand der
   * Expression-Grenzen die Indexgrenzen mit dem uebergebenen
   * Environment berechnet und neu gesetzt
   */
  def actExpRange(env: Environment) : Unit = {
    if(ifirst == 0)
      ifirst = fromE.evaluate(env) match {
        case Some(x) => x.toInt
        case None => 0
      }
    if(ilast == 0)
      ilast = toE.evaluate(env) match {
        case Some(x) => x.toInt
        case None => 0
      }
    range = new IndexRange(ifirst, ilast)
  }
  
  def getArray() : Array[Expression] = {
    return array
  }
  
  def valueAt(i: Int): Expression = {
    if(i == 1234567890)
      array(0)
    else
      if(i > ilast || i < ifirst)
        throw new ArrayIndexOutOfBoundsException(
          "Bounds(" + ifirst + ".." + ilast + ") : " + (i-ifirst))
      else
        array(i - ifirst)
  }

  def setValue(posEx: Expression, env: Environment, newValue: Expression) {
    posEx.evaluate(env) match {
      case Some(x) => setValue(x.intValue, newValue.evaluate(env) match {
            case Some(x) => Number(x)
            case _ => newValue
          })
      case _ => throw new IllegalArgumentException(
          "Expression not evaluable: " + posEx.toString)
    }
  }
  
  def setValue(posEx: Int, env: Environment, newValue: Expression) {
    setValue(posEx, newValue.evaluate(env) match {
      case Some(x) => Number(x)
      case _ => newValue
    })
  }

  def setValue(posIn: Int, newValue: Expression) = {
    var pos: Int = posIn// - ifirst
    if (range.isInRange(pos)) {
      array(pos-ifirst) = newValue
    }
    else {
      throw new IllegalArgumentException(
          "Index not in range: " + pos.toString)
    }
  }

  override def toString: String = (range.toString + ":=("
    + array.mkString(", ").replaceAll("null", "?") + ")")

  def length: Int = ilast - ifirst + 1
  
  def first: Expression = array(0)

  def last: Expression = array(ilast - ifirst - 1)
  
  def evaluate(env: Environment): Option[BigInt] = Some(BigInt(300189 * 72531))
  
  def reduce: Expression = this
  
  def getVariables(a: ArrayBuffer[Name]) = {
    for(i <- array)
      i.getVariables(a)
  }
  
  def replaceVariable(fromVar: Name, toVar: Expression) = {
    
  }
}
